package com.zhihaoliang.coroutine.buss.flow.func

import com.zhihaoliang.coroutine.util.log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import kotlin.coroutines.coroutineContext

/**
 * @author 支豪亮
 * @date 2022/10/24 16:17
 * @des Since simple().collect is called from the main thread, the body of simple's flow is also called in the main thread
 */
object FlowThreadSwitch {

    fun onThreadSwitch(mainScope: CoroutineScope){
        onThreadSwitchErro(mainScope)
        onThreadFlowOn(mainScope)
    }

    private fun onThreadSwitchErro(mainScope: CoroutineScope) = mainScope.launch {
        simpleErro().collect { value -> log("collect $value", coroutineContext) }
    }

    private fun simpleErro(): Flow<Int> =
        flow { // The WRONG way to change context for CPU-consuming code in flow builder
            try {
                kotlinx.coroutines.withContext(Dispatchers.Default) {
                    for (i in 1..3) {
                        delay(1000)
                        Thread.sleep(1000) // pretend we are computing it in CPU-consuming way
                        log("emit $i", coroutineContext)
                        emit(i) // emit next value
                    }
                }
            } catch (e: Exception) {
                log("Exception $e")
            }

        }

    private fun simple(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(1000)
            Thread.sleep(1000) // pretend we are computing it in CPU-consuming way
            log("emit $i", coroutineContext)
            emit(i) // emit next value
        }
    }.flowOn(Dispatchers.Default) // RIGHT way to change context for CPU-consuming code in flow builder

    private fun onThreadFlowOn(mainScope: CoroutineScope) = mainScope.launch {
        simple().collect { value ->
            log("collect $value", coroutineContext)
        }
    }

}